package com.link.base.base.interstatistics.controller;

import com.link.base.base.interstatistics.model.ReportInfo;
import com.link.base.base.interstatistics.model.ReportParam;
import com.link.base.base.interstatistics.model.VisitInfo;
import com.link.base.base.interstatistics.service.VisitInfoService;
import com.link.base.base.interstatistics.util.VisitStatisticsConstants;
import com.link.core.basic.annotations.JsonParam;
import com.link.core.basic.controller.BasicController;
import com.link.core.basic.service.BasicService;
import com.link.core.basic.service.KeyGenerateService;
import com.link.core.basic.service.ServiceException;
import com.link.core.cllog.LCLogger;
import com.link.core.util.RedisUtil;
import com.link.core.util.redisclient.LinkRedisClient;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * @author: 王艳
 * @date: 2018-12-13
 * @comments:
 */
@Controller
@RequestMapping("/link/visitInfo")
public class VisitInfoController extends BasicController<VisitInfo> {

    @Resource
    private KeyGenerateService keyGenerateService;

    @Resource
    private VisitInfoService visitInfoService;

    @Resource
    private DiscoveryClient discoveryClient;

    @Resource
    private RestTemplate restNoLbTemplate;

    @Override
    public BasicService<VisitInfo> getBasicService() throws Exception {
        return visitInfoService;
    }

    @RequestMapping(value = "/flushCache")
    @ResponseBody
    public Map<String, Object> flushCache(HttpSession session, HttpServletRequest request,
                                          HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        LinkRedisClient jedis = null;
        try {
            VisitInfo visitInfo = new VisitInfo();
            List<VisitInfo> list = visitInfoService.queryAll(visitInfo);
            if (list.size() == 0) {
                throw new ServiceException("INTERSTATIS-002");
            }
            visitInfo = list.get(0);
            jedis = RedisUtil.getJedis();
            String key = VisitStatisticsConstants.API_STATISTICS_CONFIG_KEY;
            //功能状态
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_STATUS, visitInfo.getStatus());
            //频率时间范围
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_LIMIT_TIME, visitInfo.getLimitTime());
            //单位时间预警请求数量
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_LIMIT_VISIT_NUM, visitInfo.getLimitVisitNum());
            //单位时间越权请求数量
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_LIMIT_AUTH_NUM, visitInfo.getLimitAuthNum());
            //是否发送短信预警
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_MSG_ALERT, visitInfo.getMsgAlert());
            //是否发送邮件预警
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_EMAIL_ALERT, visitInfo.getEmailAlert());
            //短信模板编码
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_MSG_EXAMPLE_CODE, visitInfo.getMsgExampleCode());
            //短信参数
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_MSG_PARAMS, visitInfo.getMsgParams());
            //短信类型
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_MSG_TYPE, visitInfo.getMsgType());
            //短信通知手机号
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_MSG_PHONES, visitInfo.getMsgPhones());
            //警报通知时间间隔
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_ALERT_TIME_INTERVAL, visitInfo.getAlertTimeInterval());
            //通知邮箱
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_EMAIL_ADDRS, visitInfo.getEmailAddrs());
            //是否启用超频限制
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_ACCESS_RESTRICTION, visitInfo.getAccessRestriction());
            //是否启用超频限制
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_NO_RECORD, visitInfo.getNoRecord());
            //是否启用超频限制
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_SPECIAL_URL, visitInfo.getSpecialUrl());
            //是否启用超频限制
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_SPECIAL_LIMIT_TIME, visitInfo.getSpecialLimitTime());
            //是否启用超频限制
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_SPECIAL_LIMIT_NUM, visitInfo.getSpecialLimitNum());
            //是否启用超频限制
            jedis.hset(key, VisitStatisticsConstants.API_CONFIG_SPECIAL_AUTH_NUM, visitInfo.getSpecialAuthNum());
            //登录接口访问限制次数
            jedis.hset(VisitStatisticsConstants.API_LOGIN_CONFIG,
                    VisitStatisticsConstants.API_LOGIN_LIMIT_NUM, visitInfo.getLoginLimitNum());
            //登录接口访问限制单位时间
            jedis.hset(VisitStatisticsConstants.API_LOGIN_CONFIG,
                    VisitStatisticsConstants.API_LOGIN_LIMIT_TIME, visitInfo.getLoginLimitTime());
            //登录接口访问超频报警时间间隔
            jedis.hset(VisitStatisticsConstants.API_LOGIN_CONFIG,
                    VisitStatisticsConstants.API_LOGIN_ALERT_TIME_INTERVAL, visitInfo.getLoginAlertInterval());

            List<ServiceInstance>  instances = discoveryClient.getInstances("link-gateway");
            for (ServiceInstance instance : instances) {
                String homeUrl = ((EurekaDiscoveryClient.EurekaServiceInstance) instance).getInstanceInfo().getHomePageUrl();
                String path = homeUrl + "link/frequencyControl/flushCache";
                Map<String,Boolean> respMap = restNoLbTemplate.postForObject( path ,null ,Map.class);
                if (!respMap.get("success")) {
                    result.put("success",false);
                    result.put("result",respMap.get("result"));
                    return result;
                }
            }
            result.put("success", true);
        } catch (Exception e) {
            result.put("success", false);
            result.put("result", e.getMessage());
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    /**
     * 清空redis中的访问记录
     *
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/clearRecordInCache")
    @ResponseBody
    public Map<String, Object> clearRecordInCache(HttpSession session, HttpServletRequest request,
                                                  HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        LinkRedisClient jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            for (int i = 0; i < 16; i++) {
                //jedis.select(i);
                jedis.del(VisitStatisticsConstants.VISIT_STATISTICS_KEY);
            }
            result.put("success", true);
        } catch (Exception e) {
            result.put("success", false);
            result.put("result", e.getMessage());
            LCLogger.withException(e);
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    /**
     * 查询数量
     * 包括本日，本月，总计的访问次数和越权次数
     *
     * @param visitInfo
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/queryReportOfInterfaceVisit")
    @ResponseBody
    public Map<String, Object> queryReportOfInterfaceVisit(@JsonParam VisitInfo visitInfo, HttpSession session, HttpServletRequest request,
                                                           HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        List<ReportInfo> statistics = visitInfoService.queryReportOfInterfaceVisit(visitInfo);
        result.put("success", true);
        result.put("statistic", statistics);
        return result;
    }

    /**
     * 查询接口访问总数前十
     * 包括本日，本月，总计的访问次数和越权次数
     *
     * @param param
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/queryReportOfTop10")
    @ResponseBody
    public Map<String, Object> queryReportOfTop10(@JsonParam ReportParam param, HttpSession session, HttpServletRequest request,
                                                  HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        Map<String, List<ReportInfo>> res = visitInfoService.queryReportOfTop10(param);
        result.put("success", true);
        result.put("res", res);
        return result;
    }

    /**
     * 根据日期查询接口数
     * date 日期(YYYY-MM-DD)
     *
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/queryReportByDate")
    @ResponseBody
    public Map<String, Object> queryReportByDate(@JsonParam ReportParam param, HttpSession session, HttpServletRequest request,
                                                 HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        Map<String, int[]> res = visitInfoService.queryReportByDate(param.getQueryDate());
        result.put("success", true);
        result.put("res", res);
        return result;
    }

    /**
     * 根据日期区间查询访问数
     * date 日期(YYYY-MM-DD)
     *
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/queryReportByDateRange")
    @ResponseBody
    public Map<String, Object> queryReportByDateRange(@JsonParam ReportParam param, HttpSession session, HttpServletRequest request,
                                                      HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        long start = param.getQueryDateBegin();
        long end = param.getQueryDateEnd();
        Map<String, Map<String, Integer>> res = visitInfoService.queryReportByDateRange(start,end);
        /**
         * 一下代码为了避免所有的访问类型都为空时，前端接收的值为空从而使页面图像显示不正常的问题
         * @author 郭闪
         * @date 2019/12/27
         */
        Set<String> keys = res.keySet();
        if (keys.isEmpty()) {
            Map<String, Integer> dateMap = new LinkedHashMap<>();
            long period = (end - start) / 24;
            DateTimeFormatter ftf;
            String ftfDate;
            for (int i = 0; i < 24; i++) {
                ftf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                ftfDate = ftf.format(LocalDateTime.ofInstant(Instant.ofEpochMilli(start + period * i), ZoneId.systemDefault()));
                System.out.println(i);
                dateMap.put(ftfDate, 0);
            }
            res.put("Visit",dateMap);
            res.put("PermissionOver",dateMap);
            res.put("DataChange",dateMap);
        }
        result.put("success", true);
        result.put("res", res);
        return result;
    }

    /**
     * 刷新/解除某url的访问权限
     *
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/flushRecordInCache")
    @ResponseBody
    public Map<String, Object> flushRecordInCache(@JsonParam VisitInfo visitInfo, HttpSession session, HttpServletRequest request,
                                                  HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        try {
            visitInfoService.flushRecordInCache(visitInfo);
            result.put("success", true);
        } catch (Exception e) {
            result.put("success", false);
            result.put("result", e.getMessage());
        }
        return result;
    }

    /**
     * 通过遍历redis hash，刷新/解除某url的访问权限
     * 这个方法的问题在于使用hkeys这个条件可能会造成redis阻塞
     *
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/flushAllByCache")
    @ResponseBody
    public Map<String, Object> flushAllByCache(HttpSession session, HttpServletRequest request,
                                               HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        LinkRedisClient jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            visitInfoService.flushAllByCache(jedis);
            result.put("success", true);
            result.put("message", "清空接口访问缓存记录完毕！");
        } catch (Exception e) {
            LCLogger.error().withMessageKey("flushAllInCache").withMessage("清空接口访问记录缓存时出现异常！");
            result.put("success", false);
            result.put("result", e.getMessage());
            result.put("message", "清空接口访问记录缓存时出现异常！");
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }

    /**
     * 通过数据库查询url，刷新/解除某url的访问权限
     *
     * @param session
     * @param request
     * @param response
     * @return
     */
    @RequestMapping(value = "/flushAllByDb")
    @ResponseBody
    public Map<String, Object> flushAllByDb(HttpSession session, HttpServletRequest request,
                                            HttpServletResponse response) {
        Map<String, Object> result = new HashMap<String, Object>(2);
        LinkRedisClient jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            visitInfoService.flushAllByDb(jedis);
            result.put("success", true);
            result.put("message", "清空接口访问缓存记录完毕！");
        } catch (Exception e) {
            LCLogger.error().withMessageKey("flushAllByDb").withMessage("清空接口访问记录缓存时出现异常！");
            result.put("success", false);
            result.put("result", e.getMessage());
            result.put("message", "清空接口访问记录缓存时出现异常！");
        } finally {
            RedisUtil.returnResource(jedis);
        }
        return result;
    }
}
